<?php

namespace app\models\common;

use think\Model;
use think\facade\Validate;
use think\facade\Db;
use app\common\lib\UploadFile;

class ModuleRightsModel extends Model
{
    protected $table = 'cm_module_rights';
    protected $moduleTable = 'cm_module';


    /**
     * 记录列表
     * @param array $param
     * @param int $start
     * @param int $size
     * @return array
     */
    public function getRecordList(array $param = [], int $start = 0, int $size = 10)
    {
        $childSql = "select count(*) from " . $this->table . " as c where c.parent_id=r.id and c.is_delete=0";
        if (isset($param['child_is_menu']) and $param['child_is_menu'] == 1) {
            $childSql .= " and c.is_menu=1";
        }
        if (isset($param['module_ids']) and $param['module_ids']) {
            $childSql .= ' and (c.module_id in (' . implode(',', $param['module_ids']) . ') or c.module_id=0)';
        }

        $field = [
            'r.id',
            'r.parent_id',
            'r.module_id',
            'r.right_name',
            'r.right_code',
            'r.clients_id',
            'r.is_menu',
            'r.resource',
            'r.is_show',
            'r.remark',
            'r.menu_url',
            'r.menu_icon',
            'r.sort',
            'l.name as clients_name',
            'm.name as module_name',
            Db::raw("($childSql) as child_num")
        ];
        $pdo = self::table($this->table)
            ->field($field)
            ->alias("as r ")
            ->leftJoin(['cm_clients' => 'l'], 'r.clients_id = l.id')
            ->leftJoin(['cm_module' => 'm'], 'r.module_id = m.id');
        $pdo = $this->createSearchParam($pdo, $param);
        if ($size > 0) {
            $pdo->limit($start, $size);
        }
        $list = $pdo->order('r.sort', 'asc')->order('r.id', 'desc')->select();
        $list = $list ? $list->toArray() : [];
        foreach ($list as $key => $value) {
            $list[$key]['menu_icon_url'] = UploadFile::turnSavePathToUrl($value['menu_icon']);
            $list[$key]['module_name'] = $value['module_id'] > 0 ? $value['module_name'] : '';
        }
        return $list;
    }


    /**
     * 通过id获取详情
     * @param $id
     * @param array $where
     * @return void
     */
    public function getInfoById($id, array $where = [])
    {
        $info = self::table($this->table)
            ->where(['id' => $id, 'is_delete' => 0])
            ->find();
        $info = $info ? $info->toArray() : [];
        if ($info) {
            $resource = $info['resource'] ? explode(',', $info['resource']) : [];
            $resourceList = [];
            foreach ($resource as $v) {
                $vArr = explode(':', $v);
                $resourceList[] = [
                    'http_type' => $vArr[0],
                    'path' => $vArr[1]
                ];
            }
            $info['resource_list'] = $resourceList;
            $info['menu_icon_url'] = UploadFile::turnSavePathToUrl($info['menu_icon']);
        }
        return $info;
    }

    /**
     * 通过上级Id获取下面所有子权限Id
     * @param array $parent
     * @param array $returnData
     * @return array
     */
    public function getAllChildIdByParentId(array $parent = [], array $returnData = [])
    {
        $list = $this->getRecordList(['parent_ids' => $parent]);
        if ($list) {
            $parentIdArr = [];
            foreach ($list as $v) {
                array_push($parentIdArr, $v['id']);
                $returnData[] = $v['id'];
                return $this->getAllChildIdByParentId($parentIdArr, $returnData);
            }
        }
        return $returnData;
    }

    /**
     * 添加记录
     * @param array $params
     * @return array
     */
    public function createRecord(array $params)
    {
        $checkRes = $this->checkSaveData(0, $params);
        if ($checkRes['status'] != STATUS_CODE_SUCCESS) {
            return $checkRes;
        }
        $res = self::insert($checkRes['data']);
        if (!$res) {
            return funReturn(STATUS_CODE_INSIDEERROR, '保存失败请重试');
        }
        return funReturn(STATUS_CODE_SUCCESS, 'success');
    }

    /**
     * 修改记录
     * @param $id
     * @param array $param
     * @return array
     */
    public function updateRecord($id, array $param = [])
    {
        $checkRes = $this->checkSaveData($id, $param);
        if ($checkRes['status'] != STATUS_CODE_SUCCESS) {
            return $checkRes;
        }
        $childIds = $this->getAllChildIdByParentId([$id]);

        Db::startTrans();
        try {
            $res = self::where('id', $id)->update($checkRes['data']);
            $childUpdate = true;
            if ($res) {
                if ($childIds) {
                    $childUpdate = self::whereIn('id', $childIds)->update(['module_id' => $checkRes['data']['module_id']]);
                }
            }
            if ($res !== false && $childUpdate !== false) {
                Db::commit();
                return funReturn(STATUS_CODE_SUCCESS, '保存成功');
            }
        } catch (\Exception $e) {
            Db::rollBack();
            return funReturn(STATUS_CODE_INSIDEERROR, '保存失败');
        }
    }


    /**
     * 删除数据
     * @param $id
     * @return array|bool|null
     */
    public function deleteRecord($id, array $where = [])
    {
        $childList = $this->getRecordList(['parent_id' => $id]);
        if ($childList) {
            return funReturn(STATUS_CODE_DATAERROR, '存在子权限，请先删除子权限');
        }

        $res = self::where('id', $id)->update(['is_delete' => DB::raw('id')]);
        if (!$res) {
            return funReturn(STATUS_CODE_INSIDEERROR, '删除失败请重试');
        }
        return funReturn(STATUS_CODE_SUCCESS, 'success');
    }

    /**
     * 切换是否菜单
     * @param $id
     * @param $value
     * @return array
     */
    public function switchIsMenu($id, $value)
    {
        return $this->updateField($id, 'is_menu', $value);
    }

    /**
     * 切换是否显示
     * @param $id
     * @param $value
     * @return array
     */
    public function switchIsShow($id, $value)
    {
        return $this->updateField($id, 'is_show', $value);
    }


    /**
     * 修改字段值
     * @param $id
     * @param $field
     * @param $value
     * @return array
     */
    protected function updateField($id, $field, $value)
    {
        $res = self::where('id', $id)->update([$field => $value]);
        if ($res === false) {
            return funReturn(STATUS_CODE_INSIDEERROR, '修改失败请重试');
        }
        return funReturn(STATUS_CODE_SUCCESS, 'success');
    }

    /**
     * 组装查询条件
     * @return void
     */
    private function createSearchParam($pdo, array $param = [])
    {
        $pdo->where('r.is_delete', 0);
        if (isset($param['module_id']) && intval($param['module_id']) > 0) {
            $pdo->where('r.module_id', $param['module_id']);
        }
        if (isset($param['clients_id']) && intval($param['clients_id']) > 0) {
            $pdo->where('r.clients_id', $param['clients_id']);
        }
        if (isset($param['parent_id']) && intval($param['parent_id']) >= 0) {
            $pdo->where('r.parent_id', $param['parent_id']);
        }
        if (isset($param['is_show']) && in_array($param['is_show'], [1, 0])) {
            $pdo->where('r.is_show', $param['is_show']);
        }
        if (isset($param['is_menu']) && in_array($param['is_menu'], [1, 0])) {
            $pdo->where('r.is_menu', $param['is_menu']);
        }
        if (isset($param['parent_ids'][0]) && is_array($param['parent_ids'])) {
            $pdo->whereIn('r.parent_id', $param['parent_ids']);
        }
        if (isset($param['ids'][0]) && is_array($param['ids'])) {
            $pdo->whereIn('r.id', $param['ids']);
        }
        if (isset($param['clients_ids'][0]) && is_array($param['clients_ids'])) {
            $pdo = $pdo->whereIn('r.clients_id', $param['clients_ids']);
        }

        if (isset($param['module_ids'][0]) && is_array($param['module_ids'])) {
            $pdo->where(function ($query) use ($param) {
                $query->whereIn('r.module_id', $param['module_ids'])
                    ->whereOr('r.module_id', 0);
            });
        }

        return $pdo;
    }

    /**
     * 校验数据
     * @param $id
     * @param $params
     * @return array
     * @throws \think\db\exception\DbException
     */
    private function checkSaveData($id = 0, $params = [])
    {
        $rule = [
            'right_code' => 'require|regex:[A-Za-z0-9]{5}$',
            'right_name' => 'require',
            'module_id' => 'require|integer|min:0',
            'parent_id' => 'require|integer|min:0',
            'clients_id' => 'integer|min:0',
            'sort' => 'require|integer|min:1|max:99',
        ];

        $message = [
            'right_code.require' => '编号不能为空',
            'right_code.regex' => '编号只能由字母和数字组成',
            'right_name.require' => '名称不能为空',
            'module_id.require' => '缺少所属功能',
            'module_id.integer' => '缺少所属功能',
            'module_id.min' => '请选择所属功能',
            'parent_id.require' => '缺少parent_id',
            'parent_id.integer' => 'parent_id参数只能是整型数字',
            'parent_id.min' => 'parent_id参数最小是0',
            'clients_id.integer' => 'clients_id参数只能是整型数字',
            'clients_id.min' => 'clients_id参数最小是0',
            'sort.require' => '缺少排序',
            'sort.integer' => '缺少必须为整数',
            'sort.min' => '排序不能小于1',
            'sort.max' => '排序不能大于99',
        ];

        $validate = Validate::message($message)->rule($rule);
        if (!$validate->check($params)) {
            return funReturn(STATUS_CODE_DATAERROR, $validate->getError());
        }

        $codeExist = self::where('right_code', '=', $params['right_code'])
            ->where('is_delete', '=', 0)
            ->where('id', '<>', $id)->count();
        if ($codeExist) {
            return funReturn(STATUS_CODE_DATAERROR, '编号已经存在');
        }
        $data = [
            'right_code' => $params['right_code'],
            'right_name' => $params['right_name'],
            'module_id' => $params['module_id'],
            'parent_id' => $params['parent_id'],
            'is_menu' => $params['is_menu'],
            'is_show' => $params['is_show'],
            'resource' => $params['resource'] ?? '',
            'clients_id' => isset($params['clients_id']) ? intval($params['clients_id']) : 0,
            'remark' => $params['remark'] ?? '',
            'menu_url' => $params['menu_url'] ?? '',
            'menu_icon' => $params['menu_icon'] ?? '',
            'sort' => $params['sort'],
        ];
        return funReturn(STATUS_CODE_SUCCESS, 'success', $data);
    }

}